//
// Created by Administrator on 2023/4/14.
//

#ifndef WEBRTC_MODEL_RANDOMGNERATOR_H
#define WEBRTC_MODEL_RANDOMGNERATOR_H

#include <bits/stdc++.h>

using namespace std;

/**
 * 根据离散的概率分布生成数据
 * 泛型T 输出数据的类型
 */
template<class T>
class RandomGenerator {
private:
    //区间
    struct Interval {
        //坐标
        double coordinate;
        //数据
        T data;

        Interval(double coordinate, T data) : coordinate(coordinate), data(data) {}
    };

    //分布转换成的区间
    vector<Interval> intervals;
    //最大区间右端点
    double maxIntervalEnd;
    //随机数生成器
    std::random_device randomDevice;
    //以随机数生成器初始化梅森旋转算法引擎
    std::mt19937 engine;
    //定义均匀分布
    std::uniform_real_distribution<> uniformDistribution;
public:
    /**
     * @param distribution 概率分布
     */
    explicit RandomGenerator(map<T, double> &distribution) : randomDevice(), engine(randomDevice()) {
        double intervalBegin = 0;
        for (const auto &item: distribution) {
            intervals.emplace_back(intervalBegin, item.first);
            //[intervalBegin_i,intervalBegin_{i+1})表示位于这个区间
            intervalBegin += item.second;
        }
        maxIntervalEnd = intervalBegin;
        //定义0到maxIntervalEnd的均匀分布
        uniformDistribution = std::uniform_real_distribution<>(0, maxIntervalEnd);
    }

    /**
    * @param distribution 概率分布
    */
    explicit RandomGenerator(vector<pair<T, double>> &distribution) : randomDevice(), engine(randomDevice()) {
        double intervalBegin = 0;
        for (const auto &item: distribution) {
            intervals.emplace_back(intervalBegin, item.first);
            //[intervalBegin_i,intervalBegin_{i+1})表示位于这个区间
            intervalBegin += item.second;
        }
        maxIntervalEnd = intervalBegin;
        //定义0到maxIntervalEnd的均匀分布
        uniformDistribution = std::uniform_real_distribution<>(0, maxIntervalEnd);
    }

    //获取一个随机数
    T get() {
        double random = uniformDistribution(engine);
        int l = 0;
        int r = intervals.size();
        while (l < r) {
            int mid = (l + r) >> 1;
            if (intervals[mid].coordinate > random) { r = mid; }
            else { l = mid + 1; }
        }
        return intervals[l - 1].data;
    }
};

#endif //WEBRTC_MODEL_RANDOMGNERATOR_H
